home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / hplip / ui4 / setupdialog.py < prev    next >
Encoding:
Python Source  |  2009-04-14  |  36.9 KB  |  1,031 lines

  1. # -*- coding: utf-8 -*-
  2. #
  3. # (c) Copyright 2001-2009 Hewlett-Packard Development Company, L.P.
  4. #
  5. # This program is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation; either version 2 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  18. #
  19. # Authors: Don Welch
  20. #
  21.  
  22. # StdLib
  23. import socket
  24. import operator
  25.  
  26. # Local
  27. from base.g import *
  28. from base import device, utils,  models
  29. from prnt import cups
  30. from base.codes import *
  31. from ui_utils import *
  32. #from installer import core_install
  33.  
  34. # Qt
  35. from PyQt4.QtCore import *
  36. from PyQt4.QtGui import *
  37.  
  38. # Ui
  39. from setupdialog_base import Ui_Dialog
  40. from plugindialog import PluginDialog
  41.  
  42. # Fax
  43. try:
  44.     from fax import fax
  45.     fax_import_ok = True
  46. except ImportError:
  47.     # This can fail on Python < 2.3 due to the datetime module
  48.     fax_import_ok = False
  49.     log.warning("Fax setup disabled - Python 2.3+ required.")
  50.  
  51.  
  52. PAGE_DISCOVERY = 0
  53. PAGE_DEVICES = 1
  54. PAGE_ADD_PRINTER = 2
  55. PAGE_MAX = 2
  56.  
  57. BUTTON_NEXT = 0
  58. BUTTON_FINISH = 1
  59. BUTTON_ADD_PRINTER = 2
  60.  
  61. ADVANCED_SHOW = 0
  62. ADVANCED_HIDE = 1
  63.  
  64. DEVICE_DESC_ALL = 0
  65. DEVICE_DESC_SINGLE_FUNC = 1
  66. DEVICE_DESC_MULTI_FUNC = 2
  67.  
  68.  
  69.  
  70. class DeviceTableWidgetItem(QTableWidgetItem):
  71.     def __init__(self, text, device_uri):
  72.         QTableWidgetItem.__init__(self, text, QTableWidgetItem.UserType)
  73.         self.device_uri = device_uri
  74.  
  75.  
  76.  
  77. class SetupDialog(QDialog, Ui_Dialog):
  78.     def __init__(self, parent, param, jd_port, device_uri=None):
  79.         QDialog.__init__(self, parent)
  80.         self.setupUi(self)
  81.  
  82.         self.param = param
  83.         self.jd_port = jd_port
  84.         self.device_uri = device_uri
  85.  
  86.         if device_uri:
  87.             log.info("Using device: %s" % device_uri)
  88.  
  89.         self.initUi()
  90.  
  91.         if self.skip_discovery:
  92.             QTimer.singleShot(0, self.showDevicesPage)
  93.         else:
  94.             QTimer.singleShot(0, self.showDiscoveryPage)
  95.  
  96.     #
  97.     # INIT
  98.     #
  99.  
  100.     def initUi(self):
  101.         self.setWindowIcon(QIcon(load_pixmap('prog', '48x48')))
  102.  
  103.         # connect signals/slots
  104.         self.connect(self.CancelButton, SIGNAL("clicked()"), self.CancelButton_clicked)
  105.         self.connect(self.BackButton, SIGNAL("clicked()"), self.BackButton_clicked)
  106.         self.connect(self.NextButton, SIGNAL("clicked()"), self.NextButton_clicked)
  107.         self.connect(self.ManualGroupBox,  SIGNAL("clicked(bool)"),  self.ManualGroupBox_clicked)
  108.  
  109.         self.initDiscoveryPage()
  110.         self.initDevicesPage()
  111.         self.initAddPrinterPage()
  112.  
  113.     #
  114.     #  DISCOVERY PAGE
  115.     #
  116.  
  117.     def initDiscoveryPage(self):
  118.         self.UsbRadioButton.setChecked(True)
  119.         self.setUsbRadioButton(True)
  120.         self.ManualGroupBox.setChecked(False)
  121.  
  122.         self.advanced = False
  123.         self.manual = False
  124.         self.skip_discovery = False
  125.         self.NetworkRadioButton.setEnabled(prop.net_build)
  126.         self.ParallelRadioButton.setEnabled(prop.par_build)
  127.         self.devices = {}
  128.         self.bus = 'usb'
  129.         self.timeout = 5
  130.         self.ttl = 4
  131.         self.search = ''
  132.         self.print_test_page = False
  133.         self.device_desc = DEVICE_DESC_ALL
  134.  
  135.         if self.param:
  136.             log.info("Searching for device...")
  137.             self.manual = True
  138.             self.advanced = True
  139.             self.ManualParamLineEdit.setText(self.param)
  140.             self.JetDirectSpinBox.setValue(self.jd_port)
  141.             self.ManualGroupBox.setChecked(True)
  142.             self.DiscoveryOptionsGroupBox.setEnabled(False)
  143.  
  144.             if self.manualDiscovery():
  145.                 self.skip_discovery = True
  146.             else:
  147.                 FailureUI(self, self.__tr("<b>Device not found.</b> <p>Please make sure your printer is properly connected and powered-on."))
  148.  
  149.                 match = device.usb_pat.match(self.param)
  150.                 if match is not None:
  151.                     self.UsbRadioButton.setChecked(True)
  152.                     self.setUsbRadioButton(True)
  153.  
  154.                 else:
  155.                     match = device.dev_pat.match(self.param)
  156.                     if match is not None and prop.par_build:
  157.                         self.ParallelRadioButton.setChecked(True)
  158.                         self.setParallelRadioButton(True)
  159.  
  160.                     else:
  161.                         match = device.ip_pat.match(self.param)
  162.                         if match is not None and prop.net_build:
  163.                             self.NetworkRadioButton.setChecked(True)
  164.                             self.setNetworkRadioButton(True)
  165.  
  166.                         else:
  167.                             FailureUI(self, self.__tr("<b>Invalid manual discovery parameter.</b>"))
  168.  
  169.         elif self.device_uri: # If device URI specified on the command line, skip discovery
  170.                               # if the device URI is well-formed (but not necessarily valid)
  171.             try:
  172.                 back_end, is_hp, self.bus, model, serial, dev_file, host, port = \
  173.                 device.parseDeviceURI(self.device_uri)
  174.  
  175.             except Error:
  176.                 log.error("Invalid device URI specified: %s" % self.device_uri)
  177.  
  178.             else:
  179.                 name = ''
  180.                 if self.bus == 'net':
  181.                     try:
  182.                         log.debug("Trying to get hostname for device...")
  183.                         name = socket.gethostbyaddr(host)[0]
  184.                     except socket.herror:
  185.                         log.debug("Failed.")
  186.                     else:
  187.                         log.debug("Host name=%s" % name)
  188.  
  189.                 self.devices = {self.device_uri : (model, model, name)}
  190.                 self.skip_discovery = True
  191.  
  192.         # If no network or parallel, usb is only option, skip initial page...
  193.         elif not prop.par_build and not prop.net_build:
  194.             self.skip_discovery = True
  195.             self.bus = 'usb'
  196.             self.UsbRadioButton.setChecked(True)
  197.             self.setUsbRadioButton(True)
  198.  
  199.  
  200.         self.DeviceTypeComboBox.addItem("All devices/printers", QVariant(DEVICE_DESC_ALL))
  201.         self.DeviceTypeComboBox.addItem("Single function printers only", QVariant(DEVICE_DESC_SINGLE_FUNC))
  202.         self.DeviceTypeComboBox.addItem("All-in-one/MFP devices only", QVariant(DEVICE_DESC_MULTI_FUNC))
  203.  
  204.         self.connect(self.AdvancedButton, SIGNAL("clicked()"), self.AdvancedButton_clicked)
  205.         self.connect(self.UsbRadioButton, SIGNAL("toggled(bool)"), self.UsbRadioButton_toggled)
  206.         self.connect(self.NetworkRadioButton, SIGNAL("toggled(bool)"), self.NetworkRadioButton_toggled)
  207.         self.connect(self.ParallelRadioButton, SIGNAL("toggled(bool)"), self.ParallelRadioButton_toggled)
  208.         self.connect(self.NetworkTTLSpinBox,  SIGNAL("valueChanged(int)"), self.NetworkTTLSpinBox_valueChanged)
  209.         self.connect(self.NetworkTimeoutSpinBox,  SIGNAL("valueChanged(int)"),
  210.                      self.NetworkTimeoutSpinBox_valueChanged)
  211.         self.connect(self.ManualGroupBox,  SIGNAL("toggled(bool)"),  self.ManualGroupBox_toggled)
  212.  
  213.         self.showAdvanced()
  214.  
  215.  
  216.     def ManualGroupBox_toggled(self, checked):
  217.         self.DiscoveryOptionsGroupBox.setEnabled(not checked)
  218.  
  219.  
  220.     def manualDiscovery(self):
  221.         ret = False
  222.         # Validate param...
  223.         device_uri, sane_uri, fax_uri = device.makeURI(self.param, self.jd_port)
  224.  
  225.         if device_uri:
  226.             back_end, is_hp, bus, model, serial, dev_file, host, port = \
  227.                 device.parseDeviceURI(device_uri)
  228.  
  229.             name = ''
  230.             if bus == 'net':
  231.                 try:
  232.                     name = socket.gethostbyaddr(host)[0]
  233.                 except socket.herror:
  234.                     pass
  235.  
  236.             self.devices = {device_uri : (model, model, name)}
  237.  
  238.             if bus == 'usb':
  239.                 self.UsbRadioButton.setChecked(True)
  240.                 self.setUsbRadioButton(True)
  241.  
  242.             elif bus == 'net' and prop.net_build:
  243.                 self.NetworkRadioButton.setChecked(True)
  244.                 self.setNetworkRadioButton(True)
  245.  
  246.             elif bus == 'par' and prop.par_build:
  247.                 self.ParallelRadioButton.setChecked(True)
  248.                 self.setParallelRadioButton(True)
  249.  
  250.             ret = True
  251.  
  252.         return ret
  253.  
  254.  
  255.     def ManualGroupBox_clicked(self, checked):
  256.         self.manual = checked
  257.         network = self.NetworkRadioButton.isChecked()
  258.         self.setJetDirect(network)
  259.  
  260.  
  261.     def showDiscoveryPage(self):
  262.         self.BackButton.setEnabled(False)
  263.         self.NextButton.setEnabled(True)
  264.         self.setNextButton(BUTTON_NEXT)
  265.         self.displayPage(PAGE_DISCOVERY)
  266.  
  267.  
  268.     def AdvancedButton_clicked(self):
  269.         self.advanced = not self.advanced
  270.         self.showAdvanced()
  271.  
  272.  
  273.     def showAdvanced(self):
  274.         if self.advanced:
  275.             self.AdvancedStackedWidget.setCurrentIndex(ADVANCED_SHOW)
  276.             self.AdvancedButton.setText(self.__tr("Hide Advanced Options"))
  277.             self.AdvancedButton.setIcon(QIcon(load_pixmap("minus", "16x16")))
  278.         else:
  279.             self.AdvancedStackedWidget.setCurrentIndex(ADVANCED_HIDE)
  280.             self.AdvancedButton.setText(self.__tr("Show Advanced Options"))
  281.             self.AdvancedButton.setIcon(QIcon(load_pixmap("plus", "16x16")))
  282.  
  283.  
  284.     def setJetDirect(self, enabled):
  285.         self.JetDirectLabel.setEnabled(enabled and self.manual)
  286.         self.JetDirectSpinBox.setEnabled(enabled and self.manual)
  287.  
  288.  
  289.     def setNetworkOptions(self,  enabled):
  290.         self.NetworkTimeoutLabel.setEnabled(enabled)
  291.         self.NetworkTimeoutSpinBox.setEnabled(enabled)
  292.         self.NetworkTTLLabel.setEnabled(enabled)
  293.         self.NetworkTTLSpinBox.setEnabled(enabled)
  294.  
  295.  
  296.     def setNetworkDiscovery(self, enabled):
  297.         self.NetworkDiscoveryMethodLabel.setEnabled(enabled and self.manual)
  298.         self.NetworkDiscoveryMethodComboBox.setEnabled(enabled and self.manual)
  299.  
  300.  
  301.     def UsbRadioButton_toggled(self, radio_enabled):
  302.         self.setUsbRadioButton(radio_enabled)
  303.  
  304.  
  305.     def setUsbRadioButton(self, checked):
  306.         self.setNetworkDiscovery(not checked)
  307.         self.setJetDirect(not checked)
  308.         self.setNetworkOptions(not checked)
  309.  
  310.         if checked:
  311.             self.ManualParamLabel.setText(self.__tr("USB bus ID:device ID (bbb:ddd):"))
  312.             self.bus = 'usb'
  313.             # TODO: Set bbb:ddd validator
  314.  
  315.  
  316.     def NetworkRadioButton_toggled(self, radio_enabled):
  317.         self.setNetworkRadioButton(radio_enabled)
  318.  
  319.  
  320.     def setNetworkRadioButton(self, checked):
  321.         self.setNetworkDiscovery(checked)
  322.         self.setJetDirect(checked)
  323.         self.setNetworkOptions(checked)
  324.  
  325.         if checked:
  326.             self.ManualParamLabel.setText(self.__tr("IP Address or network name:"))
  327.             self.bus = 'net'
  328.             # TODO: Reset validator
  329.  
  330.  
  331.     def ParallelRadioButton_toggled(self, radio_enabled):
  332.         self.setParallelRadioButton(radio_enabled)
  333.  
  334.  
  335.     def setParallelRadioButton(self, checked):
  336.         self.setNetworkDiscovery(not checked)
  337.         self.setJetDirect(not checked)
  338.         self.setNetworkOptions(not checked)
  339.  
  340.         if checked:
  341.             self.ManualParamLabel.setText(self.__tr("Device node (/dev/...):"))
  342.             self.bus = 'par'
  343.             # TODO: Set /dev/... validator
  344.  
  345.  
  346.     def NetworkTTLSpinBox_valueChanged(self, ttl):
  347.         self.ttl = ttl
  348.  
  349.  
  350.     def NetworkTimeoutSpinBox_valueChanged(self, timeout):
  351.         self.timeout = timeout
  352.  
  353.     #
  354.     # DEVICES PAGE
  355.     #
  356.  
  357.     def initDevicesPage(self):
  358.         self.connect(self.RefreshButton,  SIGNAL("clicked()"),  self.RefreshButton_clicked)
  359.  
  360.  
  361.     def showDevicesPage(self):
  362.         self.BackButton.setEnabled(True)
  363.         self.setNextButton(BUTTON_NEXT)
  364.  
  365.         QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
  366.         try:
  367.             if not self.devices:
  368.                 if self.manual and self.param: # manual, but not passed-in on command line
  369.                     self.manualDiscovery()
  370.  
  371.                 else: # probe
  372.                     if self.bus == 'net':
  373.                         log.info("Searching... (bus=%s, timeout=%d, ttl=%d, search=%s desc=%d)" %
  374.                                  (self.bus,  self.timeout, self.ttl, self.search or "(None)",
  375.                                   self.device_desc))
  376.                     else:
  377.                         log.info("Searching... (bus=%s, search=%s desc=%d)" %
  378.                                  (self.bus,  self.search or "(None)", self.device_desc))
  379.  
  380.                     if self.device_desc == DEVICE_DESC_SINGLE_FUNC:
  381.                         filter_dict = {'scan-type' : (operator.le, SCAN_TYPE_NONE)}
  382.  
  383.                     elif self.device_desc == DEVICE_DESC_MULTI_FUNC:
  384.                         filter_dict = {'scan-type': (operator.gt, SCAN_TYPE_NONE)}
  385.  
  386.                     else: # DEVICE_DESC_ALL
  387.                         filter_dict = {}
  388.  
  389.                     self.devices = device.probeDevices([self.bus], self.timeout, self.ttl,
  390.                                                        filter_dict, self.search)
  391.         finally:
  392.             QApplication.restoreOverrideCursor()
  393.  
  394.         #print self.devices
  395.         self.clearDevicesTable()
  396.  
  397.         if self.devices:
  398.             self.NextButton.setEnabled(True)
  399.             self.DevicesFoundIcon.setPixmap(load_pixmap('info', '16x16'))
  400.  
  401.             if len(self.devices) == 1:
  402.                 self.DevicesFoundLabel.setText(self.__tr("<b>1 device found.</b> Click <i>Next</i> to continue."))
  403.             else:
  404.                 self.DevicesFoundLabel.setText(self.__tr("<b>%1 devices found.</b> Select the device to install and click <i>Next</i> to continue.").arg(len(self.devices)))
  405.  
  406.             self.loadDevicesTable()
  407.  
  408.         else:
  409.             self.NextButton.setEnabled(False)
  410.             self.DevicesFoundIcon.setPixmap(load_pixmap('error', '16x16'))
  411.             log.error("No devices found on bus: %s" % self.bus)
  412.             self.DevicesFoundLabel.setText(self.__tr("<b>No devices found.</b><br>Click <i>Back</i> to change discovery options, or <i>Refresh</i> to search again."))
  413.  
  414.         self.displayPage(PAGE_DEVICES)
  415.  
  416.  
  417.     def loadDevicesTable(self):
  418.         self.DevicesTableWidget.setRowCount(len(self.devices))
  419.  
  420.         if self.bus == 'net':
  421.             headers = [self.__tr('Model'), self.__tr('IP Address'), self.__tr('Host Name'), self.__tr('Device URI')]
  422.             device_uri_col = 3
  423.         else:
  424.             headers = [self.__tr('Model'), self.__tr('Device URI')]
  425.             device_uri_col = 1
  426.  
  427.         self.DevicesTableWidget.setColumnCount(len(headers))
  428.         self.DevicesTableWidget.setHorizontalHeaderLabels(headers)
  429.         flags = Qt.ItemIsSelectable | Qt.ItemIsEnabled
  430.  
  431.         for row, d in enumerate(self.devices):
  432.             back_end, is_hp, bus, model, serial, dev_file, host, port = device.parseDeviceURI(d)
  433.             model_ui = models.normalizeModelUIName(model)
  434.  
  435.             i = DeviceTableWidgetItem(QString(model_ui), d)
  436.             i.setFlags(flags)
  437.             self.DevicesTableWidget.setItem(row, 0, i)
  438.  
  439.             i = QTableWidgetItem(QString(d))
  440.             i.setFlags(flags)
  441.             self.DevicesTableWidget.setItem(row, device_uri_col, i)
  442.  
  443.             if self.bus == 'net':
  444.                 i = QTableWidgetItem(QString(host))
  445.                 i.setFlags(flags)
  446.                 self.DevicesTableWidget.setItem(row, 1, i)
  447.  
  448.                 i = QTableWidgetItem(QString(self.devices[d][2]))
  449.                 i.setFlags(flags)
  450.                 self.DevicesTableWidget.setItem(row, 2, i)
  451.  
  452.         self.DevicesTableWidget.resizeColumnsToContents()
  453.         self.DevicesTableWidget.selectRow(0)
  454.         self.DevicesTableWidget.setSortingEnabled(True)
  455.         self.DevicesTableWidget.sortItems(0)
  456.  
  457.  
  458.     def clearDevicesTable(self):
  459.         self.DevicesTableWidget.clear()
  460.         self.DevicesTableWidget.setRowCount(0)
  461.         self.DevicesTableWidget.setColumnCount(0)
  462.  
  463.  
  464.     def RefreshButton_clicked(self):
  465.         self.clearDevicesTable()
  466.         self.devices = []
  467.         QTimer.singleShot(0, self.showDevicesPage)
  468.  
  469.     #
  470.     # ADD PRINTER PAGE
  471.     #
  472.  
  473.     def initAddPrinterPage(self):
  474.         self.mq = {}
  475.  
  476.         self.connect(self.PrinterNameLineEdit, SIGNAL("textEdited(const QString &)"),
  477.                      self.PrinterNameLineEdit_textEdited)
  478.  
  479.         self.connect(self.FaxNameLineEdit, SIGNAL("textEdited(const QString &)"),
  480.                      self.FaxNameLineEdit_textEdited)
  481.  
  482.         self.PrinterNameLineEdit.setValidator(PrinterNameValidator(self.PrinterNameLineEdit))
  483.         self.FaxNameLineEdit.setValidator(PrinterNameValidator(self.FaxNameLineEdit))
  484.         self.FaxNumberLineEdit.setValidator(PhoneNumValidator(self.FaxNumberLineEdit))
  485.  
  486.         self.OtherPPDButton.setIcon(QIcon(load_pixmap('folder_open', '16x16')))
  487.         self.connect(self.OtherPPDButton, SIGNAL("clicked(bool)"), self.OtherPPDButton_clicked)
  488.  
  489.         self.OtherPPDButton.setToolTip(self.__tr("Browse for an alternative PPD file for this printer."))
  490.  
  491.         self.printer_fax_names_same = False
  492.         self.printer_name = ''
  493.         self.fax_name = ''
  494.         self.fax_setup_ok = True
  495.         self.fax_setup = False
  496.  
  497.  
  498.     def showAddPrinterPage(self):
  499.        # Install the plugin if needed...
  500.         plugin = self.mq.get('plugin', PLUGIN_NONE)
  501.         if plugin > PLUGIN_NONE:
  502.             form = PluginDialog(self, plugin)
  503.             if not form.isPluginInstalled():
  504.                 form.exec_()
  505.  
  506.                 if not form.result and plugin == PLUGIN_REQUIRED:
  507.                     FailureUI(self, self.__tr("<b>The printer you are trying to setup requires a binary driver plug-in and it failed to install.</b><p>Please check you internet connection and try again.</p></p>Visit <u>http://hplipopensource.com</u> for more infomation.</p>"))
  508.                     return
  509.  
  510.         self.setNextButton(BUTTON_ADD_PRINTER)
  511.         if not self.printer_name:
  512.             self.setDefaultPrinterName()
  513.  
  514.         self.findPrinterPPD()
  515.  
  516.         if fax_import_ok and prop.fax_build and \
  517.             self.mq.get('fax-type', FAX_TYPE_NONE) not in (FAX_TYPE_NONE, FAX_TYPE_NOT_SUPPORTED):
  518.  
  519.             self.fax_setup = True
  520.             self.SetupFaxGroupBox.setChecked(True)
  521.             self.SetupFaxGroupBox.setEnabled(True)
  522.  
  523.             if not self.fax_name:
  524.                 self.setDefaultFaxName()
  525.  
  526.             self.findFaxPPD()
  527.  
  528.             self.readwriteFaxInformation()
  529.  
  530.         else:
  531.             self.SetupFaxGroupBox.setChecked(False)
  532.             self.SetupFaxGroupBox.setEnabled(False)
  533.             self.fax_name = ''
  534.             self.fax_name_ok = True
  535.             self.fax_setup = False
  536.             self.fax_setup_ok = True
  537.  
  538.         self.updatePPD()
  539.         self.setAddPrinterButton()
  540.         self.displayPage(PAGE_ADD_PRINTER)
  541.  
  542.  
  543.  
  544.  
  545.     def updatePPD(self):
  546.         if self.print_ppd is None:
  547.             log.error("No appropriate print PPD file found for model %s" % self.model)
  548.             self.PPDFileLineEdit.setText(self.__tr('(Not found. Click browse button to select a PPD file.)'))
  549.             try:
  550.                 self.PPDFileLineEdit.setStyleSheet("background-color: yellow")
  551.             except AttributeError:
  552.                 pass
  553.             self.PrinterDescriptionLineEdit.setText(QString(""))
  554.  
  555.         else:
  556.             self.PPDFileLineEdit.setText(self.print_ppd[0])
  557.             self.PrinterDescriptionLineEdit.setText(self.print_ppd[1])
  558.             try:
  559.                 self.PPDFileLineEdit.setStyleSheet("")
  560.             except AttributeError:
  561.                 pass
  562.  
  563.  
  564.     def OtherPPDButton_clicked(self, b):
  565.         ppd_file = unicode(QFileDialog.getOpenFileName(self, self.__tr("Select PPD File"),
  566.                                                        sys_conf.get('dirs', 'ppd'),
  567.                                                        self.__tr("PPD Files (*.ppd *.ppd.gz);;All Files (*)")))
  568.  
  569.         if ppd_file and os.path.exists(ppd_file):
  570.             self.print_ppd = (ppd_file, cups.getPPDDescription(ppd_file))
  571.             self.updatePPD()
  572.             self.setAddPrinterButton()
  573.  
  574.  
  575.     def findPrinterPPD(self):
  576.         QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
  577.         try:
  578.             self.print_ppd = None
  579.             self.ppds = cups.getSystemPPDs()
  580.             model = cups.stripModel2(self.model)
  581.             self.print_ppd = cups.getPPDFile2(model, self.ppds)
  582.         finally:
  583.             QApplication.restoreOverrideCursor()
  584.  
  585.  
  586.     def findFaxPPD(self):
  587.         QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
  588.         try:
  589.             log.debug("Searching for fax PPD for model %s" % self.model)
  590.  
  591.             if self.mq.get('fax-type', FAX_TYPE_NONE) == FAX_TYPE_SOAP:
  592.                 fax_ppd_name = "HP-Fax2-hplip" # Fixed width (2528 pixels) and 300dpi rendering
  593.                 nick = "HP Fax 2"
  594.             else:
  595.                 fax_ppd_name = "HP-Fax-hplip" # Standard
  596.                 nick = "HP Fax"
  597.  
  598.             ppds = []
  599.  
  600.             for f in utils.walkFiles(sys_conf.get('dirs', 'ppd'), pattern="HP-Fax*.ppd*", abs_paths=True):
  601.                 ppds.append(f)
  602.  
  603.             for f in ppds:
  604.                 if f.find(fax_ppd_name) >= 0 and cups.getPPDDescription(f) == nick:
  605.                     self.fax_ppd = f
  606.                     self.fax_setup_ok = True
  607.                     print "Found fax PPD:", f
  608.                     break
  609.             else:
  610.                 self.fax_ppd = None
  611.                 self.fax_setup_ok = False
  612.  
  613.         finally:
  614.             QApplication.restoreOverrideCursor()
  615.  
  616.  
  617.  
  618.     def setDefaultPrinterName(self):
  619.         self.installed_print_devices = device.getSupportedCUPSDevices(['hp'])
  620.         log.debug(self.installed_print_devices)
  621.  
  622.         self.installed_queues = [p.name for p in cups.getPrinters()]
  623.  
  624.         back_end, is_hp, bus, model, serial, dev_file, host, port = device.parseDeviceURI(self.device_uri)
  625.         default_model = utils.xstrip(model.replace('series', '').replace('Series', ''), '_')
  626.  
  627.         printer_name = default_model
  628.  
  629.         # Check for duplicate names
  630.         if self.device_uri in self.installed_print_devices and \
  631.             printer_name in self.installed_print_devices[self.device_uri]:
  632.                 i = 2
  633.                 while True:
  634.                     t = printer_name + "_%d" % i
  635.                     if t not in self.installed_print_devices[self.device_uri]:
  636.                         printer_name += "_%d" % i
  637.                         break
  638.                     i += 1
  639.  
  640.         self.printer_name_ok = True
  641.         self.PrinterNameLineEdit.setText(printer_name)
  642.         log.debug(printer_name)
  643.         self.printer_name = printer_name
  644.  
  645.  
  646.     def setDefaultFaxName(self):
  647.         self.installed_fax_devices = device.getSupportedCUPSDevices(['hpfax'])
  648.         log.debug(self.installed_fax_devices)
  649.  
  650.         self.fax_uri = self.device_uri.replace('hp:', 'hpfax:')
  651.  
  652.         back_end, is_hp, bus, model, serial, dev_file, host, port = device.parseDeviceURI(self.fax_uri)
  653.         default_model = utils.xstrip(model.replace('series', '').replace('Series', ''), '_')
  654.  
  655.         fax_name = default_model + "_fax"
  656.  
  657.         # Check for duplicate names
  658.         if self.fax_uri in self.installed_fax_devices and \
  659.             fax_name in self.installed_fax_devices[self.fax_uri]:
  660.                 i = 2
  661.                 while True:
  662.                     t = fax_name + "_%d" % i
  663.                     if t not in self.installed_fax_devices[self.fax_uri]:
  664.                         fax_name += "_%d" % i
  665.                         break
  666.                     i += 1
  667.  
  668.         self.fax_name_ok = True
  669.         self.FaxNameLineEdit.setText(fax_name)
  670.         self.fax_name = fax_name
  671.  
  672.  
  673.     def PrinterNameLineEdit_textEdited(self, t):
  674.         self.printer_name = unicode(t)
  675.         self.printer_name_ok = True
  676.  
  677.         if not self.printer_name:
  678.             self.PrinterNameLineEdit.setToolTip(self.__tr('You must enter a name for the printer.'))
  679.             self.printer_name_ok = False
  680.  
  681.         elif self.fax_name == self.printer_name:
  682.             s = self.__tr('The printer name and fax name must be different. Please choose different names.')
  683.             self.PrinterNameLineEdit.setToolTip(s)
  684.             self.FaxNameLineEdit.setToolTip(s)
  685.             self.fax_name_ok = False
  686.             self.printer_name_ok = False
  687.             self.printer_fax_names_same = True
  688.  
  689.         elif self.printer_name in self.installed_queues:
  690.             self.PrinterNameLineEdit.setToolTip(self.__tr('A printer already exists with this name. Please choose a different name.'))
  691.             self.printer_name_ok = False
  692.  
  693.         elif self.printer_fax_names_same:
  694.             if self.fax_name != self.printer_name:
  695.                 self.printer_fax_names_same = False
  696.                 self.printer_name_ok = True
  697.  
  698.                 self.FaxNameLineEdit.emit(SIGNAL("textChanged(const QString &)"),
  699.                             (self.FaxNameLineEdit.text(),))
  700.  
  701.         self.setIndicators()
  702.         self.setAddPrinterButton()
  703.  
  704.  
  705.     def FaxNameLineEdit_textEdited(self, t):
  706.         self.fax_name = unicode(t)
  707.         self.fax_name_ok = True
  708.  
  709.         if not self.fax_name:
  710.             self.FaxNameLineEdit.setToolTip(self.__tr('You must enter a fax name.'))
  711.             self.fax_name_ok = False
  712.  
  713.         elif self.fax_name == self.printer_name:
  714.             s = self.__tr('The printer name and fax name must be different. Please choose different names.')
  715.             self.PrinterNameLineEdit.setToolTip(s)
  716.             self.FaxNameLineEdit.setToolTip(s)
  717.             self.printer_name_ok = False
  718.             self.fax_name_ok = False
  719.             self.printer_fax_names_same = True
  720.  
  721.         elif self.fax_name in self.installed_queues:
  722.             self.FaxNameLineEdit.setToolTip(self.__tr('A fax already exists with this name. Please choose a different name.'))
  723.             self.fax_name_ok = False
  724.  
  725.         elif self.printer_fax_names_same:
  726.             if self.fax_name != self.printer_name:
  727.                 self.printer_fax_names_same = False
  728.                 self.fax_name_ok = True
  729.  
  730.                 self.PrinterNameLineEdit.emit(SIGNAL("textChanged(const QString&)"),
  731.                             (self.PrinterNameLineEdit.text(),))
  732.  
  733.         self.setIndicators()
  734.         self.setAddPrinterButton()
  735.  
  736.  
  737.     def setIndicators(self):
  738.         if self.printer_name_ok:
  739.             self.PrinterNameLineEdit.setToolTip(QString(""))
  740.             try:
  741.                 self.PrinterNameLineEdit.setStyleSheet("")
  742.             except AttributeError:
  743.                 pass
  744.         else:
  745.             try:
  746.                 self.PrinterNameLineEdit.setStyleSheet("background-color: yellow")
  747.             except AttributeError:
  748.                 pass
  749.  
  750.         if self.fax_name_ok:
  751.             self.FaxNameLineEdit.setToolTip(QString(""))
  752.             try:
  753.                 self.PrinterNameLineEdit.setStyleSheet("")
  754.             except AttributeError:
  755.                 pass
  756.         else:
  757.             try:
  758.                 self.PrinterNameLineEdit.setStyleSheet("background-color: yellow")
  759.             except AttributeError:
  760.                 pass
  761.  
  762.  
  763.     def setAddPrinterButton(self):
  764.         self.NextButton.setEnabled(self.printer_name_ok and self.fax_name_ok and
  765.                                    self.print_ppd is not None and self.fax_setup_ok)
  766.  
  767.  
  768.     #
  769.     # ADD PRINTER
  770.     #
  771.  
  772.     def addPrinter(self):
  773.         self.setupPrinter()
  774.  
  775.         if self.fax_setup:
  776.             self.setupFax()
  777.             self.readwriteFaxInformation(False)
  778.  
  779.         if self.print_test_page:
  780.             self.printTestPage()
  781.  
  782.         self.close()
  783.  
  784.  
  785.  
  786.     #
  787.     # SETUP PRINTER/FAX
  788.     #
  789.  
  790.     def setupPrinter(self):
  791.         QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
  792.         try:
  793.             if not os.path.exists(self.print_ppd[0]): # assume foomatic: or some such
  794.                 status, status_str = cups.addPrinter(self.printer_name.encode('utf8'), self.device_uri,
  795.                     self.print_location, '', self.print_ppd[0], self.print_desc)
  796.             else:
  797.                 status, status_str = cups.addPrinter(self.printer_name.encode('utf8'), self.device_uri,
  798.                     self.print_location, self.print_ppd[0], '', self.print_desc)
  799.  
  800.             log.debug("addPrinter() returned (%d, %s)" % (status, status_str))
  801.             self.installed_print_devices = device.getSupportedCUPSDevices(['hp'])
  802.  
  803.             log.debug(self.installed_print_devices)
  804.  
  805.             if self.device_uri not in self.installed_print_devices or \
  806.                 self.printer_name not in self.installed_print_devices[self.device_uri]:
  807.  
  808.                 QApplication.restoreOverrideCursor()
  809.                 FailureUI(self, self.__tr("<b>Printer queue setup failed.</b><p>Please restart CUPS and try again."))
  810.             else:
  811.                 # TODO:
  812.                 #service.sendEvent(self.hpssd_sock, EVENT_CUPS_QUEUES_CHANGED, device_uri=self.device_uri)
  813.                 pass
  814.  
  815.         finally:
  816.             QApplication.restoreOverrideCursor()
  817.  
  818.  
  819.     def setupFax(self):
  820.         QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
  821.         try:
  822.             if not os.path.exists(self.fax_ppd):
  823.                 status, status_str = cups.addPrinter(self.fax_name.encode('utf8'),
  824.                     self.fax_uri, self.fax_location, '', self.fax_ppd,  self.fax_desc)
  825.             else:
  826.                 status, status_str = cups.addPrinter(self.fax_name.encode('utf8'),
  827.                     self.fax_uri, self.fax_location, self.fax_ppd, '', self.fax_desc)
  828.  
  829.             log.debug("addPrinter() returned (%d, %s)" % (status, status_str))
  830.             self.installed_fax_devices = device.getSupportedCUPSDevices(['hpfax'])
  831.  
  832.             log.debug(self.installed_fax_devices)
  833.  
  834.             if self.fax_uri not in self.installed_fax_devices or \
  835.                 self.fax_name not in self.installed_fax_devices[self.fax_uri]:
  836.  
  837.                 QApplication.restoreOverrideCursor()
  838.                 FailureUI(self, self.__tr("<b>Fax queue setup failed.</b><p>Please restart CUPS and try again."))
  839.             else:
  840.                 pass
  841.                 # TODO:
  842.                 #service.sendEvent(self.hpssd_sock, EVENT_CUPS_QUEUES_CHANGED, device_uri=self.fax_uri)
  843.  
  844.         finally:
  845.             QApplication.restoreOverrideCursor()
  846.  
  847.  
  848.     def readwriteFaxInformation(self, read=True):
  849.         try:
  850.             QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
  851.  
  852.             d = fax.getFaxDevice(self.fax_uri, disable_dbus=True)
  853.  
  854.             while True:
  855.                 try:
  856.                     d.open()
  857.                 except Error:
  858.                     error_text = self.__tr("Unable to communicate with the device. Please check the device and try again.")
  859.                     log.error(unicode(error_text))
  860.                     if QMessageBox.critical(self,
  861.                                            self.windowTitle(),
  862.                                            error_text,
  863.                                            QMessageBox.Retry | QMessageBox.Default,
  864.                                            QMessageBox.Cancel | QMessageBox.Escape,
  865.                                            QMessageBox.NoButton) == QMessageBox.Cancel:
  866.                         break
  867.  
  868.                 else:
  869.                     try:
  870.                         tries = 0
  871.                         ok = True
  872.  
  873.                         while True:
  874.                             tries += 1
  875.  
  876.                             try:
  877.                                 if read:
  878.                                     self.fax_number = unicode(d.getPhoneNum())
  879.                                     self.fax_name_company = unicode(d.getStationName())
  880.                                 else:
  881.                                     d.setStationName(self.fax_name_company)
  882.                                     d.setPhoneNum(self.fax_number)
  883.  
  884.                             except Error:
  885.                                 error_text = self.__tr("<b>Device I/O Error</b><p>Could not communicate with device. Device may be busy.")
  886.                                 log.error(unicode(error_text))
  887.  
  888.                                 if QMessageBox.critical(self,
  889.                                                        self.windowTitle(),
  890.                                                        error_text,
  891.                                                        QMessageBox.Retry | QMessageBox.Default,
  892.                                                        QMessageBox.Cancel | QMessageBox.Escape,
  893.                                                        QMessageBox.NoButton) == QMessageBox.Cancel:
  894.                                     break
  895.  
  896.  
  897.                                 time.sleep(5)
  898.                                 ok = False
  899.  
  900.                                 if tries > 12:
  901.                                     break
  902.  
  903.                             else:
  904.                                 ok = True
  905.                                 break
  906.  
  907.                     finally:
  908.                         d.close()
  909.  
  910.                     if ok and read:
  911.                         self.FaxNumberLineEdit.setText(self.fax_number)
  912.                         self.NameCompanyLineEdit.setText(self.fax_name_company)
  913.  
  914.                     break
  915.  
  916.         finally:
  917.             QApplication.restoreOverrideCursor()
  918.  
  919.  
  920.     def printTestPage(self):
  921.         try:
  922.             d = device.Device(self.device_uri)
  923.         except Error, e:
  924.             FailureUI(self, self.__tr("<b>Device error:</b><p>%s (%s)." % (e.msg, e.opt)))
  925.  
  926.         else:
  927.             try:
  928.                 d.open()
  929.             except Error:
  930.                 FailureUI(self, self.__tr("<b>Unable to print to printer.</b><p>Please check device and try again."))
  931.             else:
  932.                 if d.isIdleAndNoError():
  933.                     d.close()
  934.  
  935.                     try:
  936.                         d.printTestPage(self.printer_name)
  937.                     except Error, e:
  938.                         if e.opt == ERROR_NO_CUPS_QUEUE_FOUND_FOR_DEVICE:
  939.                             FailureUI(self, self.__tr("<b>No CUPS queue found for device.</b><p>Please install the printer in CUPS and try again."))
  940.                         else:
  941.                             FailureUI(self, self.__tr("<b>Printer Error</b><p>An error occured: %s (code=%d)." % (e.msg, e.opt)))
  942.                 else:
  943.                     FailureUI(self, self.__tr("<b>Printer Error.</b><p>Printer is busy, offline, or in an error state. Please check the device and try again."))
  944.                     d.close()
  945.  
  946.     #
  947.     # Misc
  948.     #
  949.  
  950.     def NextButton_clicked(self):
  951.         p = self.StackedWidget.currentIndex()
  952.         if p == PAGE_DISCOVERY:
  953.             self.manual = self.ManualGroupBox.isChecked()
  954.             self.param = unicode(self.ManualParamLineEdit.text())
  955.             self.jd_port = self.JetDirectSpinBox.value()
  956.             self.search = unicode(self.SearchLineEdit.text())
  957.             self.device_desc = int(self.DeviceTypeComboBox.itemData(self.DeviceTypeComboBox.currentIndex()).toInt()[0])
  958.             self.showDevicesPage()
  959.  
  960.         elif p == PAGE_DEVICES:
  961.             row = self.DevicesTableWidget.currentRow()
  962.             self.device_uri = self.DevicesTableWidget.item(row, 0).device_uri
  963.             self.mq = device.queryModelByURI(self.device_uri)
  964.             back_end, is_hp, bus, model, serial, dev_file, host, port = device.parseDeviceURI(self.device_uri)
  965.             self.model = models.normalizeModelName(model).lower()
  966.  
  967. #            core = core_install.CoreInstall()
  968. #            core.set_plugin_version()
  969. #
  970. #            plugin = self.mq.get('plugin', PLUGIN_NONE)
  971. #            if plugin > PLUGIN_NONE and not core.check_for_plugin():
  972. #                form = PluginDialog(self, plugin)
  973. #                form.exec_()
  974.  
  975.             self.showAddPrinterPage()
  976.  
  977.         elif p == PAGE_ADD_PRINTER:
  978.             self.print_test_page = self.SendTestPageCheckBox.isChecked()
  979.             self.print_desc = unicode(self.PrinterDescriptionLineEdit.text()).encode('utf8')
  980.             self.print_location = unicode(self.PrinterLocationLineEdit.text()).encode('utf8')
  981.             self.fax_setup = self.SetupFaxGroupBox.isChecked()
  982.             self.fax_desc = unicode(self.FaxDescriptionLineEdit.text()).encode('utf8')
  983.             self.fax_location = unicode(self.FaxLocationLineEdit.text()).encode('utf8')
  984.             self.fax_name_company = unicode(self.NameCompanyLineEdit.text()).encode('utf8')
  985.             self.fax_number = unicode(self.FaxNumberLineEdit.text()).encode('utf8')
  986.             self.addPrinter()
  987.  
  988.         else:
  989.             log.error("Invalid page!") # shouldn't happen!
  990.  
  991.  
  992.     def BackButton_clicked(self):
  993.         p = self.StackedWidget.currentIndex()
  994.         if p == PAGE_DEVICES:
  995.             self.devices = {}
  996.             self.showDiscoveryPage()
  997.  
  998.         elif p == PAGE_ADD_PRINTER:
  999.             self.showDevicesPage()
  1000.  
  1001.         else:
  1002.             log.error("Invalid page!") # shouldn't happen!
  1003.  
  1004.  
  1005.     def CancelButton_clicked(self):
  1006.         self.close()
  1007.  
  1008.  
  1009.     def displayPage(self, page):
  1010.         self.updateStepText(page)
  1011.         self.StackedWidget.setCurrentIndex(page)
  1012.  
  1013.  
  1014.     def setNextButton(self, typ=BUTTON_FINISH):
  1015.         if typ == BUTTON_ADD_PRINTER:
  1016.             self.NextButton.setText(self.__tr("Add Printer"))
  1017.         elif typ == BUTTON_NEXT:
  1018.             self.NextButton.setText(self.__tr("Next >"))
  1019.         elif typ == BUTTON_FINISH:
  1020.             self.NextButton.setText(self.__tr("Finish"))
  1021.  
  1022.  
  1023.     def updateStepText(self, p):
  1024.         self.StepText.setText(self.__tr("Step %1 of %2").arg(p+1).arg(PAGE_MAX+1))
  1025.  
  1026.  
  1027.     def __tr(self,s,c = None):
  1028.         return qApp.translate("SetupDialog",s,c)
  1029.  
  1030.  
  1031.